#include "HelloWorldScene.h"

USING_NS_CC;

// 角色
#define HERO_TAG	1
#define ENEMY_TAG	2
#define HIT_LBL_TAG	3
#define DEBUG_TAG	4
#define CSBNAME_LBL_TAG	5
#define EMITIDX_LBL_TAG	6

// 按钮
#define CLOSE_BTN	1
#define PRE_BTN		2
#define NEXT_BTN	3
#define STOP_BTN	4
#define UNBIND_BTN	5
#define PLAY_PAUSE_BTN	6
#define DEBUG_BTN	7
#define CLEAR_BULLETS	8
#define ENEMY_ROTATE_BTN	9
#define CHANGE_CP_BTN	10

#define CELL_W		150
#define CELL_H		24
/**
 * @brief The MyBulletNode class 自定义的子弹。可以附加一些属性来用
 */
class MyBulletNode : public CCSprite
{
public:
	MyBulletNode(int power):m_power(power){}

	static MyBulletNode* create(int power, const char *pszFileName) {
		MyBulletNode* ret = new MyBulletNode(power);
		if (ret && ret->initWithFile(pszFileName)) {
			ret->autorelease();
			return ret;
		}
		CC_SAFE_DELETE(ret);
		return NULL;
	}

public:
	int 		m_power;
};

/*********************| functions in HelloWorld |*********************/

CCScene* HelloWorld::scene()
{
	CCScene *scene = CCScene::create();
	HelloWorld *layer = HelloWorld::create();
	scene->addChild(layer);
	return scene;
}

HelloWorld::HelloWorld() : _bindRun(false), _enemyRotate(false), _nowEmitID(0),
	_csbFileListView(NULL), _nowcsbID(0), _myBind(NULL), _useSC(false)
{ }

HelloWorld::~HelloWorld()
{
	clearBulletCache();
}

#define BTN_MAKE_CODE(_name_, _bfname_, _tag_) \
	CCMenuItemImage* _name_ = CCMenuItemImage::create(_bfname_"_n.png", _bfname_"_s.png", this, menu_selector(HelloWorld::btnsCB)); \
	pMenu->addChild(_name_, 0, _tag_);

bool HelloWorld::init()
{
	if ( !CCLayer::init() ) {
		return false;
	}
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();

	CCMenu* pMenu = CCMenu::create();
	pMenu->setPosition(CCPointZero);
	this->addChild(pMenu, 1);

	// 关闭按钮
	BTN_MAKE_CODE(pCloseItem, "close", CLOSE_BTN);
	pCloseItem->setAnchorPoint(ccp(1, 0));
	pCloseItem->setPosition(ccp(visibleSize.width, 4));

	// 解除绑定按钮
	BTN_MAKE_CODE(pUb, "unbind", UNBIND_BTN);
	pUb->setAnchorPoint(pCloseItem->getAnchorPoint());
	pUb->setPosition(ccp(pCloseItem->getPositionX(), pCloseItem->boundingBox().getMaxY() + 15));

	// 调试按钮
	BTN_MAKE_CODE(pDebug, "debug", DEBUG_BTN);
	pDebug->setAnchorPoint(pUb->getAnchorPoint());
	pDebug->setPosition(ccp(pUb->getPositionX(), pUb->boundingBox().getMaxY() + 15));

	// 碰撞方式切换按钮
	BTN_MAKE_CODE(pCP, "cp", CHANGE_CP_BTN);
	pCP->setAnchorPoint(pDebug->getAnchorPoint());
	pCP->setPosition(ccp(pDebug->getPositionX(), pDebug->boundingBox().getMaxY() + 15));
	_ty = pCP->boundingBox().getMaxY() + 8;

	// 旋转按钮
	BTN_MAKE_CODE(pRot, "rotate", ENEMY_ROTATE_BTN);
	pRot->setPosition(ccp(pRot->getContentSize().width * 1.5f + 32, pRot->getContentSize().height * 1.5f + 32));
	// 播放暂停按钮
	BTN_MAKE_CODE(pPlayPause, "play", PLAY_PAUSE_BTN);
	pPlayPause->setAnchorPoint(ccp(0.5, 0));
	pPlayPause->setPosition(ccp(pRot->getPositionX(), pRot->boundingBox().getMaxY() + 8));
	// 停止按钮
	BTN_MAKE_CODE(pStop, "stop", STOP_BTN);
	pStop->setAnchorPoint(ccp(0.5, 1));
	pStop->setPosition(ccp(pRot->getPositionX(), pRot->boundingBox().getMinY() - 8));
	// 上一个按钮
	BTN_MAKE_CODE(pPre, "pre", PRE_BTN);
	pPre->setAnchorPoint(ccp(1, 0.5));
	pPre->setPosition(ccp(pRot->boundingBox().getMinX() - 8, pRot->getPositionY()));
	// 下一个按钮
	BTN_MAKE_CODE(pNext, "next", NEXT_BTN);
	pNext->setAnchorPoint(ccp(0, 0.5));
	pNext->setPosition(ccp(pRot->boundingBox().getMaxX() + 8, pRot->getPositionY()));


	// 用来绘制子弹的批次
	_bulletBatch = CCSpriteBatchNode::create("bullet.png", 200);
	_bulletBatch->setPosition(CCPointZero);
	this->addChild(_bulletBatch);
	
	// 英雄
	CCSprite* hero = CCSprite::create("hero.png");
	hero->setPosition(ccp(visibleSize.width / 2, visibleSize.height / 2 - 200));
	this->addChild(hero, 0, HERO_TAG);

	// 敌机
	CCSprite* enemy = CCSprite::create("enemy.png");
	this->addChild(enemy, 0, ENEMY_TAG);
	enemy->setPosition(ccp(visibleSize.width / 2, visibleSize.height - 200));

	// 英雄被击中次数的显示
	_hit = 0;
	CCLabelAtlas* hitLbl = CCLabelAtlas::create("0", "nums.png", 12, 22, '0');
	hitLbl->setAnchorPoint(ccp(0.5, 0));
	hitLbl->setPosition(ccp(hero->getPositionX(), 15));
	this->addChild(hitLbl, 0, HIT_LBL_TAG);

	// 正在使用的csb文件的名字显示
	CCLabelTTF* csbnameLbl = CCLabelTTF::create("no file selected", "Arial", 25);
	csbnameLbl->setAnchorPoint(ccp(0.5, 1));
	csbnameLbl->setPosition(ccp(visibleSize.width / 2, visibleSize.height - 10));
	this->addChild(csbnameLbl, 0, CSBNAME_LBL_TAG);
	
	// 正在使用的csb文件中正在播放的弹道编号
	CCLabelTTF* emitIdxLbl = CCLabelTTF::create("0", "Arial", 20);
	emitIdxLbl->setAnchorPoint(csbnameLbl->getAnchorPoint());
	emitIdxLbl->setPosition(ccp(csbnameLbl->getPositionX(), csbnameLbl->boundingBox().getMinY() - 10));
	this->addChild(emitIdxLbl, 0, EMITIDX_LBL_TAG);
	emitIdxLbl->setColor(ccc3(73, 205, 255));

	// 初始化加载所有的绑定文件
	if (!initBind()) {
		return false;
	}

	// 获取绑定的文件列表信息
	cc2dv2::instance()->loadFilesInfo(_csbfileInfoVec);

	this->setTouchEnabled(true);
	return true;
}

void HelloWorld::ccTouchesBegan(CCSet* pTouches, CCEvent* pEvent)
{
	if (_csbFileListView && _csbFileListView->isVisible())
		return;
	CCSetIterator it = pTouches->begin();
	CCTouch* t = (CCTouch*)(*it);
	_lastPos = t->getLocation();
}

void HelloWorld::ccTouchesMoved(CCSet* pTouches, CCEvent* pEvent)
{
	if (_csbFileListView && _csbFileListView->isVisible())
		return;
	CCSetIterator it = pTouches->begin();
	CCTouch* t = (CCTouch*)(*it);
	CCSprite* hero = (CCSprite*)this->getChildByTag(HERO_TAG);
	CCPoint tmp = ccpSub(t->getLocation(), _lastPos);
	hero->setPosition(ccpAdd(hero->getPosition(), tmp));
	_lastPos = t->getLocation();
	CCDrawNode* d = (CCDrawNode*)this->getChildByTag(DEBUG_TAG);
	if (d) {
		d->setPosition(ccpAdd(d->getPosition(), tmp));
	}
}

void HelloWorld::btnsCB(CCObject* pSender)
{
	btnFunc(((CCNode*)pSender)->getTag());
}

void HelloWorld::btnFunc(int id)
{
	switch (id) {
	case PRE_BTN:
	case NEXT_BTN:
	{
		cc2dv2::LoadFilesInfo& pinfo = 	_csbfileInfoVec[_nowcsbID];
		if (1 == pinfo.objn)
			return;
		if (!strcmp(pinfo.fname.c_str(), "good4"))
			return;
		if (PRE_BTN == id) {
			if (0 == _nowEmitID) {
				_nowEmitID = pinfo.objn - 1;
			} else {
				--_nowEmitID;
			}

		} else {
			if (_nowEmitID == (pinfo.objn - 1)) {
				_nowEmitID = 0;
			} else {
				++_nowEmitID;
			}
		}
		updateEmitIdxLbl();
		// 切换弹幕
		cc2dv2::instance()->unbind(_myBind, false, false);;
		_myBind = NULL;
		bindThatCSBFile();
	}
		return;
	case ENEMY_ROTATE_BTN:
	{
		CCSprite* enemy = (CCSprite*)this->getChildByTag(ENEMY_TAG);
		if (_enemyRotate) {
			enemy->stopAllActions();
		} else {
			enemy->runAction(CCRepeatForever::create(CCRotateBy::create(5.0f, 360.0f)));
		}
		_enemyRotate = !_enemyRotate;
	}
		return;

	case PLAY_PAUSE_BTN:
		if (!_myBind) {
			bindThatCSBFile();
		}
		if (_myBind) {
			_bindRun = !_bindRun;
			cc2dv2::instance()->run(_myBind, _bindRun);
		}
		return;

	case CLEAR_BULLETS:
		cc2dv2::instance()->kakaAllBulletsOnce();
		return;

	case DEBUG_BTN:
	{
		CCDrawNode* d = (CCDrawNode*)this->getChildByTag(DEBUG_TAG);
		if (d) {
			cc2dv2::instance()->showBuDrawNode(false);
			this->removeChild(d);
		} else {
			d = CCDrawNode::create();
			this->addChild(d, 10, DEBUG_TAG);
			cc2dv2::instance()->showBuDrawNode(true);
			// 绘制飞机的
			CCSprite* s = (CCSprite*)this->getChildByTag(HERO_TAG);
			CCRECT_2_CP(s->boundingBox(), spcv);
			CCPoint ps[4];
			for (size_t i = 0; i < spcv.pnum; ++i) {
				ps[i].x = spcv.points[i].x;
				ps[i].y = COORD_Y_CONVERT(spcv.points[i].y);
			}
			d->drawPolygon(ps, spcv.pnum,ccc4f(0, 1.0f, 0, 0.2f),
			                           1, ccc4f(1.0f,0,0, 1.0f));
		}
	}
		return;

	case CHANGE_CP_BTN:
		cc2dv2::instance()->unbindAll(true, true);
		_myBind = NULL;
		clearBulletCache();
		btnFunc(PLAY_PAUSE_BTN);
		_useSC = !_useSC;
		return;
	case UNBIND_BTN:
		if (_myBind) {
			// NOTE:参数3如果负值true，参数2将被忽略。绑定将立刻解除并清除该绑定管理的子弹
			cc2dv2::instance()->unbind(_myBind, true, false);
			_myBind = NULL;
		}
		showCSBFileListPanel();
		return;

	case STOP_BTN:
		if (_myBind) {
			cc2dv2::instance()->unbind(_myBind, false, false);;
			_myBind = NULL;
		}
		return;

	case CLOSE_BTN:
		// release cc2dv2 plugin
		cc2dv2::end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
		CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
		CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
		exit(0);
#endif
#endif
		return;
	}
}

/* 生成子弹的精灵 */
void* HelloWorld::emitBullet(int buID, const char* fname, const char* objdatana)
{
	CCNode* ret = NULL;
	if (_recyBulletVec.empty()) {
		ret =  (CCNode*)(MyBulletNode::create(rand() % 100, _useSC ? "big_bullet.png" : "bullet.png"));
		ret->retain();
	} else {
		// NOTE: 你可以根据buID, fanme等信息从不同的缓冲中获取子弹
		ret = _recyBulletVec.back();
		_recyBulletVec.pop_back();
	}
	_bulletBatch->addChild(ret);
	/* 添加到显示节点里面, 如果需要可以在这里执行动画 */
	return (void*)ret;
}

/* 回收子弹的精灵 */
void HelloWorld::recycleBullet(void* bu, int buID, const char* fname, const char* objdatana)
{
	// NOTE:你可以根据buID,fname等信息讲子弹存入不同的缓冲中
	CCNode* pnode = (CCNode*)bu;
	_bulletBatch->removeChild(pnode, true);
	_recyBulletVec.push_back(pnode);
}

int HelloWorld::bulletStateCheck(BulletStateCheck_t& bs)
{
	// NOTE:下面的代码展示了如何使用CSB提供的多边形进行碰撞检测
	// 你可以使用你自己的碰撞检测方式。pstate提供了足够的信息帮助你来完成
	// 只要返回正确的子弹状态即可
	CCSprite* buSp = (CCSprite*)bs.buObj;
	CCSprite* s = (CCSprite*)this->getChildByTag(HERO_TAG);
	bool hitted = false;
	if (_useSC) {
		// 使用SC进行碰撞检测(比CP更加复杂的碰撞。可以使用一组圆和多边形进行混合碰撞)
		// 这是使用圆形和一个三角形组合的图形来
		SC_STACK(orsc);
		float r = buSp->getContentSize().height / 2;
		float c = buSp->getContentSize().width / 2;
		float a[6] = {c - r, 0, r};
		SC_add_ele(&orsc, a, SC_ELE_CIRCLE, 3);
		a[0] = -c; a[1] = 0;
		a[2] = a[4] = c - r - r;
		a[3] = r;
		a[5] = -r;
		SC_add_ele(&orsc, a, SC_ELE_POLYGON, 3);
		// 此处注释使用外接矩形
//		CCSIZE_2_SC(buSp->getContentSize(), orsc);
		SC_STACK(busc);
		SC_elebase_coll(bs.pele, &orsc, &busc);
		CCRECT_2_SC(s->boundingBox(), spsc);
		cc2dv2::instance()->drawDebugInfo(busc);
		hitted = SC_love_SC(&busc, &spsc);
	} else {
		// 使用CP进行碰撞检测
		// 获取子弹精灵的原始碰撞多边形
		CCSIZE_2_CP(buSp->getContentSize(), orcp);
		// 对原始多边形进行运算获取当下的多边形
		CP_STACK(bucp);
		CP_elebase_coll(bs.pele, &orcp, &bucp);
		// 获取飞机的边界矩形并转换成CSB的多边形
		CCRECT_2_CP(s->boundingBox(), spcp);
		// 绘制子弹的多边形
		cc2dv2::instance()->drawDebugInfo(bucp);
		// 子弹碰撞的判定
		hitted = CP_love_CP(&bucp, &spcp);
	}
	if (hitted) {
		// 发生了碰撞的处理
		++_hit;
		CCLabelAtlas* pl = (CCLabelAtlas*)this->getChildByTag(HIT_LBL_TAG);
		char buf[10] = {0};
		sprintf(buf, "%u", _hit);
		pl->setString(buf);
		// 我的自定义子弹
		MyBulletNode* mybu = (MyBulletNode*)bs.buObj;
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "%d", mybu->m_power);
		CCLabelAtlas* hurtNum = CCLabelAtlas::create(buf, "nums.png", 12, 22, '0');
		hurtNum->setScale((mybu->m_power > 50 ? mybu->m_power : 50) / 100.0f);
		hurtNum->setColor(ccRED);
		hurtNum->setAnchorPoint(ccp(0.5, 0));
		hurtNum->setPosition(ccp(s->getPositionX() + CCRANDOM_MINUS1_1() * 50, s->boundingBox().getMaxY()));
		this->addChild(hurtNum);
		hurtNum->runAction(CCSequence::create(
					   CCMoveBy::create(0.5f, ccp(0, 50)),
					   CCCallFuncN::create(this, callfuncN_selector(HelloWorld::removeNode)),
					   NULL));
		return BULLET_UPDATE_DEAD;
	}
	return BULLET_UPDATE_CONTINUE;
}

void HelloWorld::autoMachine(pos_t* out)
{
	CCSprite* hero = (CCSprite*)this->getChildByTag(HERO_TAG);
	out->x = hero->getPositionX();
	out->y = hero->getPositionY();
}

void HelloWorld::objEndCB(const CSB::BindProto::bindele_t* pe)
{
	// NOTE:可以在这里添加一些发射子弹的切换代码
	// 这个函数在弹幕的一次发射终止的时候被触发
}

void HelloWorld::tableCellTouched(CCTableView* table, CCTableViewCell* cell)
{
	_nowcsbID = cell->getIdx();
	_nowEmitID = 0;
	bindThatCSBFile();
}

CCSize HelloWorld::cellSizeForTable(CCTableView* table)
{
	return CCSizeMake(CELL_W, CELL_H);
}

unsigned int HelloWorld::numberOfCellsInTableView(CCTableView* table)
{
	return (unsigned int)_csbfileInfoVec.size();
}

CCTableViewCell*HelloWorld::tableCellAtIndex(CCTableView* table, unsigned int idx)
{
	CCTableViewCell* pcell = table->dequeueCell();
	if (pcell) {
		CCLabelTTF* l = (CCLabelTTF*)pcell->getChildByTag(0);
		l->setString(_csbfileInfoVec[idx].fname.c_str());
	} else {
		pcell = new CCTableViewCell();
		CCLabelTTF* l = CCLabelTTF::create(_csbfileInfoVec[idx].fname.c_str(), "Arial", 15);
		l->setAnchorPoint(CCPointZero);
		l->setPosition(ccp(5, 5));
		l->setColor(ccWHITE);
		pcell->addChild(l, 0, 0);
	}
	return pcell;
}

void HelloWorld::addAEmitterEle(const uint32_t NO, const float angleOff, const pos_t* posOff)
{
	ZERO_MALLOC(bele, CSB::BindProto::bindele_t);
	cc2dv2::CSMakeObjDataName(EMITTER, NO, bele->objdatana, sizeof(bele->objdatana));
	bele->flag = CSB::BindProto::OBJ_COLOR_BLEND | CSB::BindProto::BULLET_COLOR_BLEND | CSB::BindProto::UPDATE_PASSIVE;
	bele->angleOffset = angleOff;
	if (posOff) {
		memcpy(&bele->posOffset, posOff, sizeof(pos_t));
	}
	_myBind->eleList.push_back(bele);
}

bool HelloWorld::initBind()
{
	// 加载弹道文件
	static const char* csbfiles[] = {
		"bullets/accele_speed.csb",
		"bullets/action_time_step.csb",
		"bullets/adir_auto.csb",
		"bullets/automachine.csb",
		"bullets/boss37.csb",
		"bullets/boss_4.csb",
		"bullets/buaction.csb",
		"bullets/good4.csb",
		"bullets/npc_11.csb",
		"bullets/npc_22.csb",
		"bullets/test01.csb",
		"bullets/Test.csb",
		"bullets/waveAndPariticle.csb",
		"bullets/ziji.csb",
		"bullets/liaoji-01-1.csb",
		NULL
	};
	size_t i = 0;
	while (csbfiles[i]) {
		CSB_NO_RET(cc2dv2::instance()->loadfile(csbfiles[i]), false);
		++i;
	}
	return i > 0;
}

void HelloWorld::bindThatCSBFile()
{
	_bindRun = false;
	// 生成绑定信息
	cc2dv2::LoadFilesInfo& pinfo = 	_csbfileInfoVec[_nowcsbID];

	CCSprite* enemy = (CCSprite*)this->getChildByTag(ENEMY_TAG);
	_myBind = CSB::BindProto::newBind(new SimpleBindProto(static_cast<CSB::BindHelperProto*>(this), enemy),
					  pinfo.fname.c_str());
	CCLabelTTF* csbnameLbl = (CCLabelTTF*)this->getChildByTag(CSBNAME_LBL_TAG);
	csbnameLbl->setColor(ccGREEN);
	csbnameLbl->setString(pinfo.fname.c_str());

	if (strcmp(pinfo.fname.c_str(), "good4")) {
		addAEmitterEle(_nowEmitID);
	} else {
		// 多组绑定示例
		addAEmitterEle(0);
		addAEmitterEle(1);
	}

	// 执行绑定
	if (!cc2dv2::instance()->bind(_myBind)) {
		CCLog("bind failed");
		delete _myBind;
		_myBind = NULL;
		csbnameLbl->setColor(ccRED);
		return;
	}
	updateEmitIdxLbl();
	if (_csbFileListView) {
		_csbFileListView->removeFromParent();
		_csbFileListView = NULL;
	}
}

/* 显示csb文件列表的选择框 */
void HelloWorld::showCSBFileListPanel()
{
	if (!_csbFileListView) {
		_csbFileListView = CCTableView::create(this, CCSizeMake(CELL_W, CELL_H * 10));
		this->addChild(_csbFileListView, 100);
		_csbFileListView->setDelegate(this);
		CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
		_csbFileListView->setPosition(ccp(visibleSize.width - CELL_W, _ty));
		_csbFileListView->reloadData();
		_csbFileListView->setTouchEnabled(true);
	}
}

void HelloWorld::updateEmitIdxLbl()
{
	if (_csbfileInfoVec.empty())
		return;
	CCLabelTTF* p = (CCLabelTTF*)this->getChildByTag(EMITIDX_LBL_TAG);
	char buf[32] = {0};
	sprintf(buf, "%zu/%zu", _nowEmitID + 1, _csbfileInfoVec[_nowcsbID].objn);
	p->setString(buf);
}

void HelloWorld::removeNode(CCNode* n)
{
	this->removeChild(n);
}

void HelloWorld::clearBulletCache()
{
	// 遍历recyBulletVec释放内存
	for (size_t i = 0; i < _recyBulletVec.size(); ++i) {
		_recyBulletVec[i]->release();
	}
	_recyBulletVec.clear();
}
